Skip to main content

Javascript decoder

The Spirit LoRaWAN Radon Detector sends data compressed in a hex string format. To interpret this data, you need to use a JSON decoder in your LoRaWAN network server. Below is the JSON decoder that you can use to decode the payload sent by the Spirit device.

function hexToBytes(hex) {
const bytes = [];
for (let c = 0; c < hex.length; c += 2) {
bytes.push(parseInt(hex.substr(c, 2), 16));
}
return bytes;
}

function byteToBinary(byte) {
return byte.toString(2).padStart(8, "0");
}

function bytesToBinary(bytes) {
return bytes.map(byteToBinary).join("");
}

function decodeStandalone(hex) {
const bytes = hexToBytes(hex);

// ---- Helper extractors ----
function getSerieId() {
return ((bytes[3] & 0x03) << 2) | ((bytes[2] & 0xf0) >> 4);
}

function getPacketNumber() {
return ((bytes[2] & 0x0f) << 16) | (bytes[1] << 8) | bytes[0];
}

function getRadonLevel() {
return ((bytes[5] & 0x0f) << 10) | (bytes[4] << 6) | ((bytes[3] & 0xfc) >> 2);
}

function getUncertainty() {
return ((bytes[7] & 0x0f) << 12) | (bytes[6] << 4) | ((bytes[5] & 0xf0) >> 4);
}

function getTemp() {
let val = bytes[8];
return val / 2.0 - 40.0;
}

function getHumidity() {
return bytes[9] / 2.0;
}

function getPressure() {
return bytes[10] + 900;
}

function getVoltage() {
return bytes[11] * 10 + 2500;
}

function getStatusBits() {
return byteToBinary(bytes[12]);
}

function parseStatus(statusBits) {
return {
aggregatedTampering: parseInt(statusBits.substring(0, 3), 2),
tampering: statusBits[5] === "1",
errorExists: statusBits[4] === "1",
charging: statusBits[3] === "1",
onBattery: statusBits[7] === "1",
radonSensorOff: statusBits[6] === "0", // invert like Java
};
}

// ---- Build output object ----
const statusBits = getStatusBits();
const status = parseStatus(statusBits);

return {
dataFromDevice: {
measureSerieId: getSerieId(),
packetNumber: getPacketNumber(),
radonLevel: getRadonLevel(),
radonLevelUncertainty: getUncertainty(),

temperature: getTemp(),
relativeHumidity: getHumidity(),
pressure: getPressure(),
voltage: getVoltage(),

onBattery: status.onBattery,
radonSensorOn: !status.radonSensorOff,
tampering: status.tampering,
batteryCharging: status.charging,
errorExists: status.errorExists,
aggregatedTampering: status.aggregatedTampering,
},
};
}



// Example usage:
const hexInput = "EDDB211400300000813D699E22"; // replace with your real hex payload
const result = decodeStandalone(hexInput);
console.log(JSON.stringify(result, null, 2));